package com.xh.core.util;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
import com.google.common.io.Files;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.file.Paths;
import java.util.*;

/*
 * @Author daiwei
 * @Description
 * @Date 2018/9/25 18:39
 **/
public class FileUtils {

    /**
     * 获取临时文件上传路径
     * @param request
     * @return
     */
    public static String getUploadRootPath(HttpServletRequest request){
        String uploadPath=request.getSession().getServletContext().getRealPath("/");
        String relativePath="upload"+"/";
        String customPath="temp";
        relativePath+=customPath+"/";
        Date now =new Date();
        relativePath+= DateUtils.format(now,"yyyyMM")+"/";
        relativePath+= DateUtils.format(now,"dd")+"/";
        return uploadPath+relativePath;
    }

    /**
     * 创建文件路径
     * @param filePath
     */
    public static void createFileDirectory(String filePath){
        try{
            File file=new File(filePath);
            File dir=file.getParentFile();
            if(!dir.exists()){
                dir.mkdirs();
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    /**
     * 随机生成文件名（时间戳+6位随机数字）
     * @return
     */
    public static String createRandomFilename(){
        return System.currentTimeMillis()+ StringUtils.randomNumber(6);
    }

    /**
     * 随机重命名文件名
     * @param oriName
     * @return
     */
    public static String randomRenameFilename(String oriName){
        int index=oriName.lastIndexOf(".");
        if(index==-1){
            return createRandomFilename();
        }else{
            return createRandomFilename()+oriName.substring(index).toLowerCase();
        }
    }

    /**
     * 获得源文件的扩展名（不带.）
     * @param filePath
     * @return
     */
    public static String getExt(String filePath){
        int index=filePath.lastIndexOf(".");

        if(index==-1){
            return "";
        }else{
            return filePath.substring(index+1);
        }
    }

    /**
     * 获得源文件的扩展名（不带.）
     * @param filePath
     * @return
     */
    public static String getFileName(String filePath){
        int index=filePath.lastIndexOf("/");
        if(index == -1){
        	index=filePath.lastIndexOf("\\");
        }
        if(index==-1){
            return "";
        }else{
            return filePath.substring(index+1);
        }
    }


    /**
     * 获得源文件的扩展名（带.）
     * @param filePath
     * @return
     */
    public static String getExtWithPoint(String filePath){
        int index=filePath.lastIndexOf(".");

        if(index==-1){
            return "";
        }else{
            return filePath.substring(index);
        }
    }


    /**
     * 更改源文件的扩展名
     * @param filePath
     * @param newExt
     * @return
     */
    public static String changeExt(String filePath,String newExt){
        int index=filePath.lastIndexOf(".");
        if(newExt==null){
            newExt="";
        }
        newExt=newExt.trim().toLowerCase();
        if(index==-1){
            return filePath+(StringUtils.isEmpty(newExt)?"":("."+newExt));
        }else{
            return filePath.substring(0,index)+(StringUtils.isEmpty(newExt)?"":("."+newExt));
        }
    }

    /**
     * 获取目录下（包括子文件夹）所有文件
     * @param dirPath 文件夹路径
     * @param includeHidden 是否包含隐藏文件
     * @return
     */
    public static List getAllFiles(String dirPath,boolean includeHidden){
        List<File> filelist=new ArrayList<>();
        File dir = new File(dirPath);
        File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String fileName = files[i].getName();
                if (files[i].isDirectory()) { // 判断是文件还是文件夹
                    filelist.addAll(getAllFiles(files[i].getAbsolutePath(),includeHidden)); // 获取文件绝对路径
                } else {
                    if(files[i].isHidden()) {
                        if(includeHidden) {
                            filelist.add(files[i]);
                        }
                    }else{
                        filelist.add(files[i]);
                    }
                }
            }

        }
        return filelist;
    }

    /**
     * 文件列表根据扩展名、文件名进行排序
     * @param files 文件列表
     * @param sortOrder 排序方式：asc升序，其他降序
     * @return
     */
    public static List<File> sortFilesByExt(List<File> files,String sortOrder){
        Collections.sort(files, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                int extOrder=Files.getFileExtension(o1.getName()).compareTo(Files.getFileExtension(o2.getName()));
                if(extOrder!=0){
                    return (sortOrder.equals("asc")?1:-1)*Files.getFileExtension(o1.getName()).compareTo(Files.getFileExtension(o2.getName()));
                }else{
                    return (sortOrder.equals("asc")?1:-1)*o1.getName().compareTo(o2.getName());
                }
            }
        });
        return files;
    }

    /**
     * zip解压缩
     *
     * @param zipFilename
     * File 需要解压缩的文件
     * @param outputDirectory
     * String 解压后的目标目录
     */
    public static boolean unZipFiles(String zipFilename, String outputDirectory) {
        try {
            File outFile = new File(outputDirectory);
            if (!outFile.exists()) {
                outFile.mkdirs();
            }
            ZipFile zipFile = new ZipFile(zipFilename);
            Enumeration en = zipFile.getEntries();
            ZipEntry zipEntry = null;
            while (en.hasMoreElements()) {
                zipEntry = (ZipEntry) en.nextElement();
                if (zipEntry.isDirectory()) {
                    // mkdir directory
                    String dirName = zipEntry.getName();
                    // System.out.println("=dirName is:=" + dirName + "=end=");
                    dirName = dirName.substring(0, dirName.length() - 1);
                    File f = new File(outFile.getPath() + File.separator + dirName);
                    f.mkdirs();
                } else {
                    // unzip file
                    String strFilePath = outFile.getPath() + File.separator + zipEntry.getName();
                    File f = new File(strFilePath);
                    // the codes remedified by can_do on 2010-07-02 =begin=
                    // /////begin/////
                    // 判断文件不存在的话，就创建该文件所在文件夹的目录
                    if (!f.exists()) {
                        String[] arrFolderName = zipEntry.getName().split("/");
                        String strRealFolder = "";
                        for (int i = 0; i < (arrFolderName.length - 1); i++) {
                            strRealFolder += arrFolderName[i] + File.separator;
                        }
                        strRealFolder = outFile.getPath() + File.separator + strRealFolder;
                        File tempDir = new File(strRealFolder);
                        // 此处使用.mkdirs()方法，而不能用.mkdir()
                        tempDir.mkdirs();
                    }
                    // ////end///
                    // the codes remedified
                    f.createNewFile();
                    System.out.println("zipEntry====="+JSONObject.toJSONString(zipEntry));
                    System.out.println("zipFile===="+JSONObject.toJSONString(zipFile));
                    InputStream in = zipFile.getInputStream(zipEntry);
                    System.out.println("in" + JSONObject.toJSONString(in));
                    FileOutputStream out = new FileOutputStream(f);
                    System.out.println("out====="+JSONObject.toJSONString(out));
                    try {
                        int c;
                        byte[] by = new byte[1024];
                        while ((c = in.read(by)) != -1) {
                            out.write(by, 0, c);
                        }
                        out.flush();
                    } catch (IOException e) {
                        throw e;
                    } finally {
                        if(out!=null){
                            out.close();
                        }
                        if(in!=null){
                            in.close();
                        }
                    }
                }
            }
            if(zipFile!=null){
                zipFile.close();
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 下载文件
     * @param url
     * @param saveFileName
     * @param outPath
     * @return
     */
    public static String downloadFile(String url,String saveFileName,String outPath){
        if(Strings.isNullOrEmpty(url) || Strings.isNullOrEmpty(outPath)) {
            return null;
        }
        Closer closer = Closer.create();
        try {
            File outputDir = new File(outPath);
            if(!outputDir.exists()) {
                outputDir.mkdirs();
            }
            String fileName =  saveFileName;
            if(StringUtils.isEmpty(fileName)) {
                fileName = org.apache.commons.lang3.StringUtils.substringBefore(url, "?");
                fileName = org.apache.commons.lang3.StringUtils.substringAfterLast(fileName, "/");
            }
            File file = new File(outputDir, fileName);
            if(!file.exists()||(file.length()==0&&file.canWrite())){
                InputStream in = closer.register(new URL(url).openStream());
                byte[] bytes= ByteStreams.toByteArray(in);
                java.nio.file.Files.write(Paths.get(file.getPath()),bytes);
            }
            return file.getAbsolutePath();
        } catch(Exception ex) {
            ex.printStackTrace();
            return null;
        } finally {
            try {
                closer.close();
            } catch (IOException e) {
                closer = null;
            }
        }
    }

    /**
     * 下载文件
     * @param filename
     * @param path
     * @return
     */
    public static void downloadLocalFile(String filename,String path, HttpServletResponse response){
        try {
            HttpHeaders headers = new HttpHeaders();
            File file = new File(path);
            filename=(StringUtils.isEmpty(filename)?file.getName():filename);
            filename= URLDecoder.decode(filename, "UTF-8");
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", filename);
            if(file.exists()) {
                // 取得文件的后缀名。
                String ext = FileUtils.getExt(path);
                InputStream fis = new BufferedInputStream(new FileInputStream(file));   //用BufferedInputStream读取文件
                response.reset();
                response.setContentType("application/x-download");
                response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes(), "iso-8859-1") + "." + ext);
                response.setHeader("Content-Length", "" + file.length());
                OutputStream os = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                byte[] buffer = new byte[1024];
                int i = -1;
                while ((i = fis.read(buffer)) != -1) {   //不能一次性读完，大文件会内存溢出（不能直接fis.read(buffer);）
                    os.write(buffer, 0, i);
                }
                fis.close();
                os.flush();
                os.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据byte数组，生成文件
     */
    public static void saveFile(byte[] bfile, String filePath) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            file = new File(filePath);
            File dir = file.getParentFile();
            if(!dir.exists()&&dir.isDirectory()){//判断文件目录是否存在
                dir.mkdirs();
            }
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 根据文件路径删除文件
     * @param path 文件路径<包括文件名和后缀>
     * @author tongchengyu add 20180314
     */
    public static void delFile(String path)
    {
        File file = new File(path);
        if(file.exists()&&file.isFile())
            file.delete();
    }


    public static byte[] toByteArray(String filename) throws IOException {
    	 
        File f = new File(filename);
        if (!f.exists()) {
            throw new FileNotFoundException(filename);
        }
 
        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(f));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            bos.close();
        }
    }
}
